#pragma once

#ifdef __cplusplus
extern "C"
{
#endif

    /*
     * SPDX-FileCopyrightText: 2019-2021 Espressif Systems (Shanghai) CO LTD
     *
     * SPDX-License-Identifier: Apache-2.0
     */

#include "driver/gpio.h"
#include "esp_check.h"
#include "esp_eth.h"
#include "esp_log.h"
#include "esp_rom_gpio.h"
#include "esp_rom_sys.h"
#include "eth_phy_regs_struct.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>

    /**
     * @brief PSCSR(PHY Special Control Status Register)
     *
     */
    typedef union
    {
        struct
        {
            uint32_t reserved1 : 2;        /* Reserved */
            uint32_t speed_indication : 3; /* Speed Indication */
            uint32_t reserved2 : 1;        /* Reserved */
            uint32_t enable_4b5b : 1;      /* Enable 4B5B encoder (only LAN8740A/LAN8741A) */
            uint32_t reserved3 : 5;        /* Reserved */
            uint32_t auto_nego_done : 1;   /* Auto Negotiation Done */
            uint32_t reserved4 : 3;        /* Reserved */
        };
        uint32_t val;
    } pscsr_reg_t;
#define ETH_PHY_CH182_PHY_STATUS_REG_ADDR (0x00)
    typedef struct
    {
        esp_eth_phy_t parent;
        esp_eth_mediator_t *eth;
        int addr;
        uint32_t reset_timeout_ms;
        uint32_t autonego_timeout_ms;
        eth_link_t link_status;
        int reset_gpio_num;
    } phy_ch182_t;

    static esp_err_t ch182_update_link_duplex_speed(phy_ch182_t *ch182);

    static esp_err_t ch182_set_mediator(esp_eth_phy_t *phy, esp_eth_mediator_t *eth);

    static esp_err_t ch182_get_link(esp_eth_phy_t *phy);

    static esp_err_t ch182_reset(esp_eth_phy_t *phy);

    static esp_err_t ch182_reset_hw(esp_eth_phy_t *phy);

    /**
     * @note This function is responsible for restarting a new auto-negotiation,
     *       the result of negotiation won't be relected to uppler layers.
     *       Instead, the negotiation result is fetched by linker timer, see `ch182_get_link()`
     */
    static esp_err_t ch182_negotiate(esp_eth_phy_t *phy);

    static esp_err_t ch182_pwrctl(esp_eth_phy_t *phy, bool enable);

    static esp_err_t ch182_set_addr(esp_eth_phy_t *phy, uint32_t addr);

    static esp_err_t ch182_get_addr(esp_eth_phy_t *phy, uint32_t *addr);

    static esp_err_t ch182_del(esp_eth_phy_t *phy);

    static esp_err_t ch182_advertise_pause_ability(esp_eth_phy_t *phy, uint32_t ability);

    static esp_err_t ch182_loopback(esp_eth_phy_t *phy, bool enable);

    static esp_err_t ch182_init(esp_eth_phy_t *phy);

    static esp_err_t ch182_deinit(esp_eth_phy_t *phy);

    esp_eth_phy_t *esp_eth_phy_new_ch182(const eth_phy_config_t *config);

#ifdef __cplusplus
}
#endif